home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Online / Term / Extras / Source / term-source.lha / FileBuffer.c < prev    next >
C/C++ Source or Header  |  1996-10-20  |  20KB  |  1,030 lines

  1. /*
  2. **    FileBuffer.c
  3. **
  4. **    Double-buffered file I/O routines
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* Argument types. */
  17.  
  18. enum    {    ARG_NAME,ARG_MODE };
  19. enum    {    ARG_OFFSET,ARG_ORIGIN };
  20.  
  21.     /* Seek offsets. */
  22.  
  23. enum    {    SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
  24.  
  25.     /* Command codes. */
  26.  
  27. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  28.  
  29.     /* OpenFileWithMode(STRPTR Name,STRPTR ModeString):
  30.      *
  31.      *    Open a plain AmigaDOS file and turn the stdio mode string
  32.      *    into the appropriate Open() mode.
  33.      */
  34.  
  35. STATIC BPTR
  36. OpenFileWithMode(STRPTR Name,STRPTR ModeString)
  37. {
  38.     LONG Mode;
  39.  
  40.     switch(ModeString[0])
  41.     {
  42.         case 'r':
  43.  
  44.             if(ModeString[1] == '+')
  45.                 Mode = MODE_READWRITE;
  46.             else
  47.                 Mode = MODE_OLDFILE;
  48.  
  49.             break;
  50.  
  51.         case 'w':
  52.  
  53.             if(ModeString[1] == '+')
  54.             {
  55.                 BPTR SomeLock;
  56.  
  57.                 if(SomeLock = Lock(Name,EXCLUSIVE_LOCK))
  58.                 {
  59.                     UnLock(SomeLock);
  60.  
  61.                     if(!DeleteFile(Name))
  62.                         return(NULL);
  63.                 }
  64.  
  65.                 Mode = MODE_READWRITE;
  66.             }
  67.             else
  68.                 Mode = MODE_NEWFILE;
  69.  
  70.             break;
  71.  
  72.         case 'a':
  73.  
  74.             return(OpenToAppend(Name,NULL));
  75.  
  76.         default:
  77.  
  78.             return(NULL);
  79.     }
  80.  
  81.     return(Open(Name,Mode));
  82. }
  83.  
  84.     /* ObtainInfo(struct Buffer *File):
  85.      *
  86.      *    Obtain information on the disk a buffered file
  87.      *    resides on.
  88.      */
  89.  
  90. STATIC VOID
  91. ObtainInfo(struct Buffer *File)
  92. {
  93.         /* Lock on the path available? */
  94.  
  95.     if(File->InfoPort)
  96.     {
  97.             /* This is more or less a trick; we try to obtain
  98.              * information on a filing system without having a
  99.              * shared lock on it. We cannot DupLockFromFH()
  100.              * the file handle since it was allocated for
  101.              * exclusive access. The ACTION_DISK_INFO packet
  102.              * solves this problem as it requires only the
  103.              * filing system task (MsgPort) to be given.
  104.              */
  105.  
  106.         if(!DoPkt(File->InfoPort,ACTION_DISK_INFO,MKBADDR(&File->InfoData),0,0,0,0))
  107.         {
  108.             File->InfoData.id_NumBlocks        = 0;
  109.             File->InfoData.id_BytesPerBlock    = 0;
  110.         }
  111.     }
  112. }
  113.  
  114.     /* FileBufferServer():
  115.      *
  116.      *    Background process to handle the buffering
  117.      *    of a filehandle, automatically gets invoked
  118.      *    when a file is opened.
  119.      */
  120.  
  121. STATIC VOID SAVE_DS
  122. FileBufferServer(VOID)
  123. {
  124.     BOOL Terminated,Done,WasFull;
  125.     struct Buffer *Buffer;
  126.     struct MsgPort *Port;
  127.     struct Process *Me;
  128.     UBYTE *String;
  129.     LONG Length;
  130.     APTR Data;
  131.  
  132.     Terminated = FALSE;
  133.  
  134.         /* Wait for startup message (-> Buffer). */
  135.  
  136.     Me = (struct Process *)FindTask(NULL);
  137.  
  138.     Port = &Me->pr_MsgPort;
  139.  
  140.     WaitPort(Port);
  141.  
  142.     Buffer = (struct Buffer *)GetMsg(Port);
  143.  
  144.         /* Open the file and obtain a filehandle. */
  145.  
  146.     String = (STRPTR)Buffer->ActionData[ARG_MODE];
  147.  
  148.         /* Put the message into the list. */
  149.  
  150.     ObtainSemaphore(&DoubleBufferSemaphore);
  151.  
  152.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  153.  
  154.     ReleaseSemaphore(&DoubleBufferSemaphore);
  155.  
  156.         /* Remember the opening date. */
  157.  
  158.     DateStamp(&Buffer->OpenDate);
  159.  
  160.         /* Check for the open type. */
  161.  
  162.     Buffer->WriteAccess = (BOOL)(String[0] != 'r');
  163.  
  164.     Buffer->FileHandle = OpenFileWithMode((STRPTR)Buffer->ActionData[ARG_NAME],String);
  165.  
  166.         /* Clear signal bit. */
  167.  
  168.     ClrSignal(SIG_COMMAND);
  169.  
  170.         /* Did the file open? */
  171.  
  172.     if(Buffer->FileHandle)
  173.     {
  174.         Buffer->Data        = Buffer->DataBuffer[0];
  175.         Buffer->DataCount    = 1;
  176.         Buffer->Fresh        = TRUE;
  177.  
  178.             /* If not in write mode fill the buffers. */
  179.  
  180.         if(!Buffer->WriteAccess)
  181.         {
  182.                 /* Fill the first one synchronously. */
  183.  
  184.             Buffer->ReadBufFull        = Read(Buffer->FileHandle,Buffer->Data,Buffer->BufLength);
  185.             Buffer->Read            = TRUE;
  186.             Buffer->RealPosition    = Buffer->ReadBufFull;
  187.  
  188.                 /* Restart caller. */
  189.  
  190.             Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  191.  
  192.                 /* Fill the second buffe asynchronously. */
  193.  
  194.             Buffer->DataLength[1]     = Buffer->Cached = Read(Buffer->FileHandle,Buffer->DataBuffer[1],Buffer->BufLength);
  195.             Buffer->RealPosition    += Buffer->Cached;
  196.         }
  197.         else
  198.         {
  199.             Buffer->InfoPort = ((struct FileHandle *)BADDR(Buffer->FileHandle))->fh_Type;
  200.  
  201.             ObtainInfo(Buffer);
  202.  
  203.             Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  204.         }
  205.     }
  206.     else
  207.         Terminated = TRUE;
  208.  
  209.         /* Go into loop waiting for commands. */
  210.  
  211.     while(!Terminated)
  212.     {
  213.         Wait(SIG_COMMAND);
  214.  
  215.         Done = FALSE;
  216.  
  217.         Buffer->Result = 0;
  218.  
  219.             /* Take care of each action. */
  220.  
  221.         switch(Buffer->Action)
  222.         {
  223.                 /* Close the file, flush any dirty
  224.                  * buffers and exit.
  225.                  */
  226.  
  227.             case BUF_CLOSE:
  228.  
  229.                 Buffer->Result = TRUE;
  230.  
  231.                 if(Buffer->BufPosition && Buffer->Written)
  232.                 {
  233.                     if(Write(Buffer->FileHandle,Buffer->Data,Buffer->BufPosition) != Buffer->BufPosition)
  234.                         Buffer->Result = FALSE;
  235.                 }
  236.  
  237.                 if(!Close(Buffer->FileHandle))
  238.                     Buffer->Result = FALSE;
  239.  
  240.                 Terminated = TRUE;
  241.  
  242.                 break;
  243.  
  244.                 /* Seek to a specific file position. */
  245.  
  246.             case BUF_SEEK:
  247.  
  248.                 Buffer->Result = 0;
  249.  
  250.                     /* Do nothing if buffer is still
  251.                      * untouched and we are required
  252.                      * to seek back to the beginning
  253.                      * of the file.
  254.                      */
  255.  
  256.                 if(Buffer->Fresh && !Buffer->ActionData[ARG_OFFSET] && Buffer->ActionData[ARG_ORIGIN] == SEEKFILE_SET)
  257.                 {
  258.                     Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  259.  
  260.                     Done = TRUE;
  261.                 }
  262.                 else
  263.                 {
  264.                     Buffer->WriteBufFull    = Buffer->BufLength;
  265.                     Buffer->Read            = FALSE;
  266.  
  267.                     if(Buffer->BufPosition && Buffer->Written)
  268.                     {
  269.                         if(Write(Buffer->FileHandle,Buffer->Data,Buffer->BufPosition) != Buffer->BufPosition)
  270.                             Buffer->Result = -1;
  271.                         else
  272.                             ObtainInfo(Buffer);
  273.                     }
  274.  
  275.                     if(!Buffer->Result)
  276.                     {
  277.                         Buffer->Result = Buffer->RealPosition - (Buffer->ReadBufFull + Buffer->Cached);
  278.  
  279.                         switch(Buffer->ActionData[ARG_ORIGIN])
  280.                         {
  281.                             case SEEKFILE_SET:
  282.  
  283.                                 if(Seek(Buffer->FileHandle,Buffer->ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  284.                                     Buffer->RealPosition = Buffer->ActionData[ARG_OFFSET];
  285.                                 else
  286.                                     Buffer->Result = -1;
  287.  
  288.                                 break;
  289.  
  290.                             case SEEKFILE_CURR:
  291.  
  292.                                 if(!Buffer->WriteAccess && Buffer->ActionData[ARG_OFFSET] >= 0 && Buffer->ReadBufFull - Buffer->ActionData[ARG_OFFSET] >= 0)
  293.                                 {
  294.                                     Buffer->ReadBufFull    -= Buffer->ActionData[ARG_OFFSET];
  295.                                     Buffer->Data        += Buffer->ActionData[ARG_OFFSET];
  296.  
  297.                                     Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  298.  
  299.                                     Done = TRUE;
  300.  
  301.                                     break;
  302.                                 }
  303.  
  304.                                 if(Seek(Buffer->FileHandle,-(Buffer->ReadBufFull + Buffer->Cached) + Buffer->ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  305.                                     Buffer->RealPosition += -(Buffer->ReadBufFull + Buffer->Cached) + Buffer->ActionData[ARG_OFFSET];
  306.                                 else
  307.                                     Buffer->Result = -1;
  308.  
  309.                                 break;
  310.  
  311.                             case SEEKFILE_END:
  312.  
  313.                                 if(Seek(Buffer->FileHandle,Buffer->ActionData[ARG_OFFSET],OFFSET_END) != -1)
  314.                                     Buffer->RealPosition = Seek(Buffer->FileHandle,0,OFFSET_CURRENT);
  315.                                 else
  316.                                     Buffer->Result = -1;
  317.  
  318.                                 break;
  319.  
  320.                             default:
  321.  
  322.                                 Buffer->Result = -1;
  323.                         }
  324.  
  325.                         Buffer->ReadBufFull = 0;
  326.  
  327.                         if(Buffer->Result != -1)
  328.                         {
  329.                             Buffer->Data        = Buffer->DataBuffer[0];
  330.                             Buffer->DataCount    = 1;
  331.  
  332.                             if(!Buffer->WriteAccess)
  333.                             {
  334.                                 Buffer->ReadBufFull         = Read(Buffer->FileHandle,Buffer->Data,Buffer->BufLength);
  335.                                 Buffer->WriteBufFull     = 0;
  336.                                 Buffer->Read             = TRUE;
  337.                                 Buffer->RealPosition    += Buffer->ReadBufFull;
  338.  
  339.                                 if(Buffer->ReadBufFull)
  340.                                 {
  341.                                     Buffer->Cached = Buffer->DataLength[1] = Read(Buffer->FileHandle,Buffer->DataBuffer[1],Buffer->BufLength);
  342.  
  343.                                     Buffer->RealPosition += Buffer->Cached;
  344.                                 }
  345.                             }
  346.                         }
  347.                         else
  348.                             Buffer->LastActionFailed = TRUE;
  349.                     }
  350.                     else
  351.                         Buffer->ReadBufFull = 0;
  352.  
  353.                     Buffer->BufPosition    = 0;
  354.                     Buffer->Written    = FALSE;
  355.                 }
  356.  
  357.                 break;
  358.  
  359.                 /* Fill the buffer with fresh data. */
  360.  
  361.             case BUF_FILL:
  362.  
  363.                 Buffer->Data            = Buffer->DataBuffer[Buffer->DataCount];
  364.                 Buffer->ReadBufFull        = Buffer->DataLength[Buffer->DataCount];
  365.                 Buffer->WriteBufFull    = 0;
  366.                 Buffer->BufPosition        = 0;
  367.                 Buffer->Read            = TRUE;
  368.                 Buffer->Written            = FALSE;
  369.                 Buffer->Fresh            = FALSE;
  370.  
  371.                 if(Buffer->ReadBufFull)
  372.                     WasFull = TRUE;
  373.                 else
  374.                     WasFull = FALSE;
  375.  
  376.                     /* The buffer contents have been
  377.                      * swapped, now wake the caller
  378.                      * up and fill the next buffer
  379.                      * asynchronously.
  380.                      */
  381.  
  382.                 Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  383.  
  384.                 Done = TRUE;
  385.  
  386.                 if(WasFull)
  387.                 {
  388.                     Buffer->DataCount = (Buffer->DataCount + 1) % BUFFER_NUMBER;
  389.  
  390.                     Buffer->Cached = Buffer->DataLength[Buffer->DataCount] = Read(Buffer->FileHandle,Buffer->DataBuffer[Buffer->DataCount],Buffer->BufLength);
  391.  
  392.                     Buffer->RealPosition += Buffer->Cached;
  393.  
  394.                     if(!Buffer->DataLength[Buffer->DataCount])
  395.                     {
  396.                         if(IoErr())
  397.                             Buffer->LastActionFailed = TRUE;
  398.                     }
  399.                 }
  400.  
  401.                 break;
  402.  
  403.                 /* Flush the contents of the buffer to disk. */
  404.  
  405.             case BUF_FLUSH:
  406.  
  407.                 if(Buffer->BufPosition && Buffer->Written)
  408.                 {
  409.                     Data                    = Buffer->Data;
  410.                     Length                    = Buffer->BufPosition;
  411.  
  412.                     Buffer->Data            = Buffer->DataBuffer[Buffer->DataCount];
  413.                     Buffer->DataCount        = (Buffer->DataCount + 1) % BUFFER_NUMBER;
  414.  
  415.                     Buffer->ReadBufFull        = 0;
  416.                     Buffer->WriteBufFull    = Buffer->BufLength;
  417.                     Buffer->BufPosition        = 0;
  418.                     Buffer->Read            = FALSE;
  419.                     Buffer->Written            = FALSE;
  420.  
  421.                     Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  422.  
  423.                     Done = TRUE;
  424.  
  425.                     if(Write(Buffer->FileHandle,Data,Length) != Length)
  426.                         Buffer->LastActionFailed = TRUE;
  427.                     else
  428.                     {
  429.                         ObtainInfo(Buffer);
  430.  
  431.                         Buffer->RealPosition += Length;
  432.                     }
  433.                 }
  434.                 else
  435.                 {
  436.                     Buffer->ReadBufFull        = 0;
  437.                     Buffer->WriteBufFull    = Buffer->BufLength;
  438.                     Buffer->BufPosition        = 0;
  439.                     Buffer->Read            = FALSE;
  440.                     Buffer->Written            = FALSE;
  441.                 }
  442.  
  443.                 Buffer->Fresh = FALSE;
  444.  
  445.                 break;
  446.         }
  447.  
  448.             /* Ring back if necessary. */
  449.  
  450.         if(!Done && !Terminated)
  451.             Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  452.     }
  453.  
  454.         /* Remove the message from the list. */
  455.  
  456.     ObtainSemaphore(&DoubleBufferSemaphore);
  457.  
  458.     Remove((struct Node *)Buffer);
  459.  
  460.     ReleaseSemaphore(&DoubleBufferSemaphore);
  461.  
  462.         /* Lock & quit. */
  463.  
  464.     Forbid();
  465.  
  466.     Signal((struct Task *)Buffer->Caller,SIG_HANDSHAKE);
  467. }
  468.  
  469.     /* BufferFill(struct Buffer *Buffer):
  470.      *
  471.      *    Fills a given buffer with fresh data.
  472.      */
  473.  
  474. STATIC BOOL
  475. BufferFill(struct Buffer *Buffer)
  476. {
  477.     if(Buffer->LastActionFailed)
  478.         return(FALSE);
  479.     else
  480.     {
  481.         if(!Buffer->ReadBufFull)
  482.         {
  483.             Buffer->Action = BUF_FILL;
  484.  
  485.             ShakeHands((struct Task *)Buffer->Child,SIG_COMMAND);
  486.         }
  487.  
  488.         return(TRUE);
  489.     }
  490. }
  491.  
  492.     /* IsValidBuffer(struct Buffer *Buffer):
  493.      *
  494.      *    Scans the double buffered file list for
  495.      *    a valid entry.
  496.      */
  497.  
  498. STATIC BOOL
  499. IsValidBuffer(struct Buffer *Buffer)
  500. {
  501.     struct Node *Node;
  502.     BOOL GotIt;
  503.  
  504.     ObtainSemaphore(&DoubleBufferSemaphore);
  505.  
  506.     GotIt = FALSE;
  507.  
  508.     for(Node = DoubleBufferList.lh_Head ; Node->ln_Succ ; Node = Node->ln_Succ)
  509.     {
  510.         if(Buffer == (struct Buffer *)Node)
  511.         {
  512.             GotIt = TRUE;
  513.  
  514.             break;
  515.         }
  516.     }
  517.  
  518.     ReleaseSemaphore(&DoubleBufferSemaphore);
  519.  
  520.     return(GotIt);
  521. }
  522.  
  523.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  524.      *
  525.      *    Open simple (unbuffered) file.
  526.      */
  527.  
  528. STATIC struct Buffer *
  529. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  530. {
  531.     struct Buffer *Buffer;
  532.  
  533.         /* Allocate buffer handle (dummy). */
  534.  
  535.     if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  536.     {
  537.             /* Provide basic information. */
  538.  
  539.         DateStamp(&Buffer->OpenDate);
  540.  
  541.         Buffer->WriteAccess = (BOOL)(AccessMode[0] != 'r');
  542.  
  543.         Buffer->SimpleIO = TRUE;
  544.  
  545.         Buffer->FileHandle = OpenFileWithMode(Name,AccessMode);
  546.  
  547.             /* Did we succeed in opening the file? */
  548.  
  549.         if(Buffer->FileHandle)
  550.         {
  551.                 /* To keep track of the free space still
  552.                  * available on the filing system.
  553.                  */
  554.  
  555.             if(Buffer->WriteAccess)
  556.             {
  557.                 Buffer->InfoPort = ((struct FileHandle *)BADDR(Buffer->FileHandle))->fh_Type;
  558.  
  559.                 ObtainInfo(Buffer);
  560.             }
  561.  
  562.                 /* Link the file into the list. */
  563.  
  564.             ObtainSemaphore(&DoubleBufferSemaphore);
  565.  
  566.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  567.  
  568.             ReleaseSemaphore(&DoubleBufferSemaphore);
  569.  
  570.             return(Buffer);
  571.         }
  572.         else
  573.             FreeVecPooled(Buffer);
  574.     }
  575.  
  576.     return(NULL);
  577. }
  578.  
  579.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  580.      *
  581.      *    Open double-buffered file.
  582.      */
  583.  
  584. STATIC struct Buffer *
  585. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  586. {
  587.     struct Buffer *Buffer;
  588.     LONG Size;
  589.  
  590.     Size = (Config->MiscConfig->IOBufferSize + 15) & ~15;
  591.  
  592.     if(Size < 2048)
  593.         Size = 2048;
  594.  
  595.         /* Allocate the buffer data. */
  596.  
  597.     do
  598.     {
  599.         Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + ((Size + 15) & ~15) * BUFFER_NUMBER + 15,MEMF_ANY | MEMF_CLEAR);
  600.  
  601.         Size /= 2;
  602.     }
  603.     while(!Buffer && Size > 2048);
  604.  
  605.     if(Buffer)
  606.     {
  607.         struct Process *Process;
  608.         LONG i;
  609.  
  610.             /* Set up the first buffer. */
  611.  
  612.         Buffer->DataBuffer[0] = (UBYTE *)(((ULONG)(Buffer + 1) + 15) & ~15);
  613.  
  614.             /* Set up the individual buffers. */
  615.  
  616.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  617.             Buffer->DataBuffer[i] = Buffer->DataBuffer[i - 1] + Size;
  618.  
  619.         Buffer->BufLength        = Size;
  620.         Buffer->WriteBufFull    = Buffer->BufLength;
  621.  
  622.             /* Create the asynchronous file server. */
  623.  
  624.         if(!(Process = CreateNewProcTags(
  625.             NP_Entry,        FileBufferServer,
  626.             NP_Name,        "term File Process",
  627.             NP_WindowPtr,    -1,
  628.         TAG_DONE)))
  629.         {
  630.             FreeVecPooled(Buffer);
  631.  
  632.             return(NULL);
  633.         }
  634.  
  635.             /* Set up the message header. */
  636.  
  637.         Buffer->Message.mn_Length        = sizeof(struct Buffer);
  638.  
  639.         Buffer->ActionData[ARG_NAME]    = (LONG)Name;
  640.         Buffer->ActionData[ARG_MODE]    = (LONG)AccessMode;
  641.  
  642.         Buffer->Child    = Process;
  643.         Buffer->Caller    = (struct Process *)FindTask(NULL);
  644.  
  645.         Forbid();
  646.  
  647.             /* Send it to the waiting server process. */
  648.  
  649.         PutMsg(&Process->pr_MsgPort,&Buffer->Message);
  650.  
  651.             /* Wait for ringback. */
  652.  
  653.         WaitForHandshake();
  654.  
  655.         Permit();
  656.  
  657.             /* Do we have a valid filehandle? */
  658.  
  659.         if(!Buffer->FileHandle)
  660.         {
  661.             FreeVecPooled(Buffer);
  662.  
  663.             return(NULL);
  664.         }
  665.         else
  666.             return(Buffer);
  667.     }
  668.  
  669.     return(NULL);
  670. }
  671.  
  672.     /* BPrintf():
  673.      *
  674.      *    Prints text into a buffered file.
  675.      */
  676.  
  677. LONG
  678. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  679. {
  680.     UBYTE    String[256];
  681.     va_list    VarArgs;
  682.  
  683.     va_start(VarArgs,Format);
  684.     LimitedVSPrintf(sizeof(String),String,Format,VarArgs);
  685.     va_end(VarArgs);
  686.  
  687.     return(BufferWrite(Buffer,String,strlen(String)));
  688. }
  689.  
  690.     /* BufferFlush(struct Buffer *Buffer):
  691.      *
  692.      *    Flush the contents of a given buffer to disk.
  693.      */
  694.  
  695. BOOL
  696. BufferFlush(struct Buffer *Buffer)
  697. {
  698.     if(Buffer->LastActionFailed)
  699.         return(FALSE);
  700.     else
  701.     {
  702.         if(Buffer->BufPosition && Buffer->Written)
  703.         {
  704.             Buffer->Action = BUF_FLUSH;
  705.  
  706.             ShakeHands((struct Task *)Buffer->Child,SIG_COMMAND);
  707.         }
  708.  
  709.         return(TRUE);
  710.     }
  711. }
  712.  
  713.     /* BufferClose(struct Buffer *Buffer):
  714.      *
  715.      *    Close a buffered filehandle.
  716.      */
  717.  
  718. BOOL
  719. BufferClose(struct Buffer *Buffer)
  720. {
  721.     if(IsValidBuffer(Buffer))
  722.     {
  723.         BOOL Success;
  724.  
  725.             /* Unbuffered file handle? */
  726.  
  727.         if(Buffer->SimpleIO)
  728.         {
  729.                 /* Close the file. */
  730.  
  731.             if(Close(Buffer->FileHandle))
  732.                 Success = TRUE;
  733.             else
  734.                 Success = FALSE;
  735.  
  736.                 /* Unlink the handle. */
  737.  
  738.             ObtainSemaphore(&DoubleBufferSemaphore);
  739.  
  740.             Remove((struct Node *)Buffer);
  741.  
  742.             ReleaseSemaphore(&DoubleBufferSemaphore);
  743.         }
  744.         else
  745.         {
  746.             Buffer->Action = BUF_CLOSE;
  747.  
  748.             ShakeHands((struct Task *)Buffer->Child,SIG_COMMAND);
  749.  
  750.             Success = Buffer->Result;
  751.         }
  752.  
  753.         FreeVecPooled(Buffer);
  754.  
  755.         return(Success);
  756.     }
  757.     else
  758.         return(FALSE);
  759. }
  760.  
  761.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  762.      *
  763.      *    Open a file for buffered I/O.
  764.      */
  765.  
  766. struct Buffer *
  767. BufferOpen(STRPTR Name,STRPTR AccessMode)
  768. {
  769.         /* Simple file handling? */
  770.  
  771.     if(Config->MiscConfig->SimpleIO)
  772.         return(OpenFileSimple(Name,AccessMode));
  773.     else
  774.     {
  775.         struct Buffer *Buffer;
  776.  
  777.             /* Try to open a buffered file, if unsuccessful
  778.              * fall back to simple file I/O.
  779.              */
  780.  
  781.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  782.             Buffer = OpenFileSimple(Name,AccessMode);
  783.  
  784.         return(Buffer);
  785.     }
  786. }
  787.  
  788.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  789.      *
  790.      *    Move the read/write pointer to a specific position
  791.      *    in a file (not really buffered).
  792.      */
  793.  
  794. BOOL
  795. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  796. {
  797.     if(Buffer->SimpleIO)
  798.     {
  799.         if(Seek(Buffer->FileHandle,Offset,Origin) == -1)
  800.             return(FALSE);
  801.         else
  802.             return(TRUE);
  803.     }
  804.     else
  805.     {
  806.         Buffer->Action                    = BUF_SEEK;
  807.         Buffer->ActionData[ARG_OFFSET]    = Offset;
  808.         Buffer->ActionData[ARG_ORIGIN]    = Origin;
  809.  
  810.         ShakeHands((struct Task *)Buffer->Child,SIG_COMMAND);
  811.  
  812.         if(Buffer->Result == -1)
  813.             return(FALSE);
  814.         else
  815.             return(TRUE);
  816.     }
  817. }
  818.  
  819.     /* BufferRead():
  820.      *
  821.      *    Read data from a file (buffered).
  822.      */
  823.  
  824. LONG
  825. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  826. {
  827.     if(Buffer->SimpleIO)
  828.     {
  829.         LONG Bytes;
  830.  
  831.         Buffer->Used = TRUE;
  832.  
  833.         if((Bytes = Read(Buffer->FileHandle,Destination,Size)) < 0)
  834.             Bytes = 0;
  835.  
  836.         return(Bytes);
  837.     }
  838.     else
  839.     {
  840.         LONG BytesRead,ToCopy,BufPosition,ReadBufFull;
  841.         UBYTE *Data;
  842.  
  843.         BytesRead = 0;
  844.  
  845.             /* If there is still data to be written in
  846.              * the buffer, write it.
  847.              */
  848.  
  849.         if(Buffer->Written)
  850.         {
  851.             if(!BufferFlush(Buffer))
  852.                 return(0);
  853.         }
  854.  
  855.             /* Set up for read access. */
  856.  
  857.         BufPosition        = Buffer->BufPosition;
  858.         ReadBufFull        = Buffer->ReadBufFull;
  859.         Data            = &Buffer->Data[BufPosition];
  860.  
  861.             /* Remember access. */
  862.  
  863.         Buffer->Used    = TRUE;
  864.  
  865.             /* Continue until all data has been processed. */
  866.  
  867.         while(Size)
  868.         {
  869.                 /* Determine number of bytes to transfer. */
  870.  
  871.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  872.             {
  873.                 CopyMem(Data,Destination,ToCopy);
  874.  
  875.                 Size        -= ToCopy;
  876.                 BufPosition    += ToCopy;
  877.                 ReadBufFull    -= ToCopy;
  878.                 Destination    += ToCopy;
  879.                 Data        += ToCopy;
  880.                 BytesRead    += ToCopy;
  881.             }
  882.             else
  883.             {
  884.                     /* Refill buffer with data. */
  885.  
  886.                 Buffer->BufPosition    = BufPosition;
  887.                 Buffer->ReadBufFull    = ReadBufFull;
  888.  
  889.                 if(!BufferFill(Buffer))
  890.                     return(BytesRead);
  891.  
  892.                 if(!Buffer->ReadBufFull)
  893.                 {
  894.                     Buffer->BufPosition = BufPosition;
  895.  
  896.                     return(BytesRead);
  897.                 }
  898.  
  899.                     /* Pick up new data. */
  900.  
  901.                 BufPosition        = Buffer->BufPosition;
  902.                 ReadBufFull        = Buffer->ReadBufFull;
  903.                 Data            = Buffer->Data;
  904.             }
  905.         }
  906.  
  907.             /* Install new data. */
  908.  
  909.         Buffer->BufPosition    = BufPosition;
  910.         Buffer->ReadBufFull    = ReadBufFull;
  911.  
  912.         return(BytesRead);
  913.     }
  914. }
  915.  
  916.     /* BufferWrite():
  917.      *
  918.      *    Write data to a file (buffered).
  919.      */
  920.  
  921. LONG
  922. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  923. {
  924.     if(Buffer->SimpleIO)
  925.     {
  926.         LONG Bytes;
  927.  
  928.         Buffer->Used = TRUE;
  929.  
  930.         Buffer->WriteAccess = TRUE;
  931.  
  932.         if((Bytes = Write(Buffer->FileHandle,Source,Size)) < 0)
  933.             Bytes = 0;
  934.         else
  935.         {
  936.             Buffer->BufPosition += Bytes;
  937.  
  938.             if(Buffer->BufPosition >= Config->MiscConfig->IOBufferSize)
  939.             {
  940.                 Buffer->BufPosition = 0;
  941.  
  942.                 ObtainInfo(Buffer);
  943.             }
  944.         }
  945.  
  946.         return(Bytes);
  947.     }
  948.     else
  949.     {
  950.         LONG BytesWritten,ToCopy,BufPosition,WriteBufFull;
  951.         UBYTE *Data;
  952.  
  953.         BytesWritten = 0;
  954.  
  955.             /* If there is still read data in the buffer,
  956.              * reset the control information.
  957.              */
  958.  
  959.         if(Buffer->Read)
  960.         {
  961.             Buffer->WriteBufFull    = Buffer->BufLength;
  962.             Buffer->BufPosition        = 0;
  963.             Buffer->Read            = FALSE;
  964.         }
  965.  
  966.             /* Set up for write access. */
  967.  
  968.         Buffer->Written = TRUE;
  969.  
  970.         BufPosition        = Buffer->BufPosition;
  971.         WriteBufFull    = Buffer->WriteBufFull;
  972.         Data            = &Buffer->Data[BufPosition];
  973.  
  974.             /* Remember access. */
  975.  
  976.         Buffer->Used    = TRUE;
  977.  
  978.             /* Continue until all data has been processed. */
  979.  
  980.         while(Size)
  981.         {
  982.                 /* Determine number of bytes to transfer. */
  983.  
  984.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  985.             {
  986.                 CopyMem(Source,Data,ToCopy);
  987.  
  988.                 Size            -= ToCopy;
  989.                 BufPosition        += ToCopy;
  990.                 WriteBufFull    -= ToCopy;
  991.                 Source            += ToCopy;
  992.                 Data            += ToCopy;
  993.                 BytesWritten    += ToCopy;
  994.             }
  995.             else
  996.             {
  997.                     /* Flush the contents of the
  998.                      * write buffer.
  999.                      */
  1000.  
  1001.                 Buffer->BufPosition        = BufPosition;
  1002.                 Buffer->WriteBufFull    = WriteBufFull;
  1003.  
  1004.                 if(!BufferFlush(Buffer))
  1005.                     return(BytesWritten);
  1006.  
  1007.                     /* Pick up new data. */
  1008.  
  1009.                 BufPosition        = Buffer->BufPosition;
  1010.                 WriteBufFull    = Buffer->WriteBufFull;
  1011.                 Data            = Buffer->Data;
  1012.  
  1013.                     /* Important - or BufferFlush() won't
  1014.                      * write the final buffer contents when
  1015.                      * the buffered file handle is freed up.
  1016.                      */
  1017.  
  1018.                 Buffer->Written = TRUE;
  1019.             }
  1020.         }
  1021.  
  1022.             /* Install new data. */
  1023.  
  1024.         Buffer->BufPosition        = BufPosition;
  1025.         Buffer->WriteBufFull    = WriteBufFull;
  1026.  
  1027.         return(BytesWritten);
  1028.     }
  1029. }
  1030.